﻿// src : http://www.codeproject.com/Articles/64975/Detect-Internet-Network-Availability
// Modified  : http://stackoverflow.com/questions/520347/c-sharp-how-do-i-check-for-a-network-connection

namespace Util.Net {
    using System;
    using System.Net.NetworkInformation;
    using System.Runtime.CompilerServices;
    
    public static class NetworkStatus {
        private static bool isAvailable;
        private static NetworkStatusChangedHandler handler;


        static NetworkStatus() {
            isAvailable = IsNetworkAvailable();
        }

        public static event NetworkStatusChangedHandler AvailabilityChanged {
            [MethodImpl(MethodImplOptions.Synchronized)]
            add {
                if (handler == null) {
                    NetworkChange.NetworkAvailabilityChanged += new NetworkAvailabilityChangedEventHandler(DoNetworkAvailabilityChanged);
                    NetworkChange.NetworkAddressChanged += new NetworkAddressChangedEventHandler(DoNetworkAddressChanged);
                }
                handler = (NetworkStatusChangedHandler)Delegate.Combine(handler, value);
            }

            [MethodImpl(MethodImplOptions.Synchronized)]
            remove {
                handler = (NetworkStatusChangedHandler)Delegate.Remove(handler, value);

                if (handler == null) {
                    NetworkChange.NetworkAvailabilityChanged -= new NetworkAvailabilityChangedEventHandler(DoNetworkAvailabilityChanged);
                    NetworkChange.NetworkAddressChanged -= new NetworkAddressChangedEventHandler(DoNetworkAddressChanged);
                }
            }
        }


        public static bool IsAvailable {
            get { return isAvailable; }
        }
        
        private static bool IsNetworkAvailable() {

            if (!NetworkInterface.GetIsNetworkAvailable())
                return false;

            NetworkInterface[] interfaces = NetworkInterface.GetAllNetworkInterfaces();
            foreach (NetworkInterface ni in interfaces) { 

                if ((ni.OperationalStatus != OperationalStatus.Up) ||
                    (ni.NetworkInterfaceType == NetworkInterfaceType.Loopback) ||
                    (ni.NetworkInterfaceType == NetworkInterfaceType.Tunnel))
                    continue;

                if (ni.Speed < 10000000)
                    continue;

                if ((ni.Description.IndexOf("virtual", StringComparison.OrdinalIgnoreCase) >= 0) ||
                    (ni.Name.IndexOf("virtual", StringComparison.OrdinalIgnoreCase) >= 0))
                    continue;

                IPv4InterfaceStatistics statistics = ni.GetIPv4Statistics();
                
                if ((statistics.BytesReceived > 0) && (statistics.BytesSent > 0)) {
                    return true;
                }
            }
            return false;
        }


        private static void DoNetworkAddressChanged(object sender, EventArgs e) {
            SignalAvailabilityChange(sender);
        }


        private static void DoNetworkAvailabilityChanged(object sender, NetworkAvailabilityEventArgs e) {
            SignalAvailabilityChange(sender);
        }


        private static void SignalAvailabilityChange(object sender) {
            bool change = IsNetworkAvailable();

            if (change != isAvailable) {
                isAvailable = change;

                if (handler != null) {
                    handler(sender, new NetworkStatusChangedArgs(isAvailable));
                }
            }
        }
    }

    public class NetworkStatusChangedArgs : EventArgs {
        private bool isAvailable;

        public NetworkStatusChangedArgs(bool isAvailable) { this.isAvailable = isAvailable; }

        public bool IsAvailable { get { return isAvailable; } }
    }

    public delegate void NetworkStatusChangedHandler(object sender, NetworkStatusChangedArgs e);
}




